-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: support ESM projects using TypeScript with ts-node/esm #22118
Conversation
Thanks for taking the time to open a PR!
|
Test summaryRun details
View run in Cypress Dashboard ➡️ Flakiness
This comment has been generated by cypress-bot as a result of this project's GitHub integration settings. You can manage this integration in this project's settings in the Cypress Dashboard |
this.options.ctx.onError(cypressError, title) | ||
}, | ||
this.options.ctx.onWarning, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code is the same, I just spaced it out so it's easier to read.
@@ -1,4 +1,3 @@ | |||
// @ts-check | |||
// this module is responsible for loading the plugins file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For some reason this caused errors to be raised when using ts-node/esm
, I don't quite know why, so I just removed the @ts-check
. These files are not very type safe anyway, I don't think the ts-check
is doing too much with the very lax tsconfig.json
in packages/server
, anyway. We can work on making it nice and strict in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want ts-node/esm/transpile-only
?
https://github.com/TypeStrong/ts-node/blob/main/esm/transpile-only.mjs
@@ -238,6 +240,37 @@ export class ProjectConfigIpc extends EventEmitter { | |||
|
|||
debug('fork child process %o', { CHILD_PROCESS_FILE_PATH, configProcessArgs, childOptions: _.omit(childOptions, 'env') }) | |||
|
|||
let isProjectUsingESModules = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this solution should any code be removed? I'm not super familiar with this code, but it seems like we might have some dead references esbuild code if this block takes over that responsibility. You mention a couple of places in your explanation, can we clean any of those up?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do think we can clean up some of the esbuild
code (it's not working properly; we could delete it all, if we decide not to go down the esbuild route).
I figured I'd leave it untouched and make the changes as minimal as possible here. Having read your comment, I'm thinking we delete it, and bring it back when re-visiting #22074.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried removing the esbuild
code path here: f1ed508. We can revisit how best to use esbuild, if users want to use it, in the near future.
system-tests/projects/config-cjs-and-esm/config-with-ts-module/tsconfig.json
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit confused with how we are dealing with esm. This PR adds the ts-node/esm
loader to where we start the config process, but we still register ts-node in the child process and then still use esbuild to require the user's config. We now have three places where configure ts/esm...
Can we not have one place for all this ts/esm logic?
@ZachJW34 good point on the "register I think we should just run the entire sub-process with As for |
@ZachJW34 I tried to improve the module loading logic and move it to one place. Here's what I came up with: cypress/packages/data-context/src/data/ProjectConfigIpc.ts Lines 260 to 290 in dcd80ae
Basically: if (has typescript) {
if (esModules) {
NODE_OPTIONS = `--loader ts-node/esm`
} else {
// we have some custom logic for our `ts_node` util, so we need to --require
// it so the code executes (cannot do this with `--loader`).
// I am not sure if we need it for `ts-node/esm`.
NODE_OPTIONS = `--require @packages/server/..../register_ts_node`
}
} else {
// typescript not available, cannot use ts-node.
// just use native Node.js loader
} Now instead of registering |
@@ -110,25 +96,16 @@ function run (ipc, file, projectRoot) { | |||
debug('User is loading an ESM config file') | |||
|
|||
try { | |||
debug('Trying to use esbuild to run their config file.') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed this for now, we can definitely integration w/ the user's esbuild, but I think that should be done separately, since there's some unknowns.
I've called out this code deletion and referenced it in the esbuild
issue so we don't forget about it: #22074
cc @tgriesser since I think you have some ideas around if/how we integrate esbuild
. I think this is a lower priority in general, since not that many people are using esbuild (without TS) vs those using TS with Cypress (who can happily use the ts-node
workflow).
// FIXME: need to validate that TS is checked once when ts is not found as well | ||
it.skip('checks for typescript only once if typescript module was not found') | ||
}) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't register ts-node in the child process anymore, instead, we run the child process with --require server/lib...../register_ts_node
. This also means we don't need the check to avoid the double registration anymore.
0929544
to
e175ee1
Compare
I spent most of the day dealing with windows bugs. I ended up reverting a few things, seems like it's mostly fine now (albeit a little CI flake). |
e175ee1
to
4f6701d
Compare
Even after this fix, I still get I am using this on a nextJS project. It doesn't/can't have |
We changed the target in cypress's tsconfig from "es5" to "es2019" to get it working. |
@chinchang can you open a new issue with a reproduction? This issue was specifically for ESM support, which means projects with No changes should be required. If it's not working as expected, it's a bug and I will fix it for you. I've used Cypress 10 with Next.js projects before, but Next.js projects come in many different configurations - please share your reproduction in a new issue and tag me. 🙏 We are pushing out fixes as soon as they are ready 👍 Also @geoffrey-adeo - I see you 👍 the issue, if you are encountering a similar problem, please create an issue explaining how to reproduce and I can look into it. |
…io#22118) * fix: support ESM projects using TypeScript with ts-node/esm * better error handling * fix test * indentation * register ts-node via --require hook * be less aggressive with erroring * update fix system tests * remove obsolete test * handle case of not using typescript * replicate 9.x behavior for legacy plugins w/ ts-node * make test project valid and adjust tests accordingly * use ts-node/esm transpile only * dummy * extract util function * merge in refactor using projectFixtureDirectory * fix test
I also see the TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts"
at Loader.defaultGetFormat [as _getFormat] (internal/modules/esm/get_format.js:65:15)
at Loader.getFormat (internal/modules/esm/loader.js:113:42)
at Loader.getModuleJob (internal/modules/esm/loader.js:244:31)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async Loader.import (internal/modules/esm/loader.js:178:17) This is in a project that worked fine with v10.0.3; I made no changes other than upgrading to 10.3.0 and I see this issue. We use yarn v2 and TypeScript - maybe this is related to yarn v2's different behavior with Happy to give more info if it's helpful, let me know what I can do! |
@a-churchill a minimal reproduction would be super useful. If you could provide that, I can definitely take a look. I'm surprised |
In my case, with a default Cypress setup in an evironment that doesn't provide typescript will result in this error. If typescript is provided (either in locap package.json or linked globally), it's all good. |
The default config is only TS if you have it installed, otherwise we default to JS. A default setup should definitely not error. How do I repro - just create a new project, install Cypress, and open it? This works for me -- what Node.js version do you have? |
[ERR_UNKNOWN_FILE_EXTENSION]
error #22096User facing changelog
Support TypeScript projects using
"type": "module"
usingts-node/esm
.Additional details
The problem is if you are using
"type": "module"
, Node.js will use it's ESM loader to load your code. If you are using ats
extension, which Node.js does not know about out of the box, you get the various errors we've seen reported.The original solution was to use
esbuild
to try load TS files if the initialrequire('cypress.config...
) failed, but it's not working as expected, as explained here. I removed theesbuild
code path for now. I noted this here so we can bring it back in the future, if needed.The solution introduced here is to use the ESM support that
ts-node
ships, as recommended in #21939. We rely onts-node
in the project and already ship it, so it makes sense to continue to use it where we can.Steps to test
[ERR_UNKNOWN_FILE_EXTENSION]
error #22096 with the latest binary from npm and verify problemHow has the user experience changed?
Can correctly load
cypress.config.ts
for"type": "module"
projects.The workflow is now:
The old workflow (shows problem):
Show old workflow diagram
PR Tasks
cypress-documentation
?type definitions
?